package com.snail.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.snail.dto.VideoCommentDTO;
import com.snail.mapper.BizCourseVideoCommentMapper;
import com.snail.model.pojo.study.BizCourseVideoComment;
import com.snail.service.BizCourseVideoCommentService;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Date 2025/8/13 11:52
 * @Author yangming
 * @Description 针对表【Biz_course_video_comment(评论表)】的数据库操作Service实现
 **/
@Service
public class BizCourseVideoCommentServiceImpl extends ServiceImpl<BizCourseVideoCommentMapper, BizCourseVideoComment>
        implements BizCourseVideoCommentService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 保存评论到Redis，并更新评论计数（使用Long类型ID）
     */
    @Override
    public void saveCommentToRedis(VideoCommentDTO commentDTO) {
        // 生成Long类型评论ID（可通过雪花算法或数据库自增获取）
        Long commentId = generateLongCommentId(); // 关键：使用Long类型ID
        // 设置ID到DTO
        commentDTO.setId(commentId);
        // 保存评论到Redis（键使用Long类型ID）
        String redisKey = RedisConstant.VIDEO_COMMENT_PREFIX + commentDTO.getVideoId() + ":" + commentId;
        redisTemplate.opsForValue().set(redisKey, commentDTO, 7, TimeUnit.DAYS);
        // 更新Redis中的评论计数
        String countKey = RedisConstant.VIDEO_COMMENT_COUNT_PREFIX + commentDTO.getVideoId();
        redisTemplate.opsForValue().increment(countKey, 1);
        redisTemplate.expire(countKey, 7, TimeUnit.DAYS);
        redisTemplate.opsForList().rightPush(RedisConstant.COMMENT_SYNC_QUEUE, commentDTO);
    }

    /**
     * 从Redis查询视频评论
     */
    @Override
    public List<Object> getCommentsFromRedis(Long videoId) {
        String pattern = RedisConstant.VIDEO_COMMENT_PREFIX + videoId + ":*";
        return redisTemplate.keys(pattern).stream()
                .map(key -> redisTemplate.opsForValue().get(key))
                .toList();
    }

    /**
     * 同步Redis评论到数据库（Long类型ID适配）
     */
    @Override
    public void syncCommentsToDb() {
        while (true) {
            Object obj = redisTemplate.opsForList().leftPop(RedisConstant.COMMENT_SYNC_QUEUE, 1, TimeUnit.SECONDS);
            if (obj == null) {
                break;
            }
            VideoCommentDTO dto = (VideoCommentDTO) obj;
            BizCourseVideoComment comment = new BizCourseVideoComment();
            comment.setId(dto.getId()); // 直接使用Long类型ID
            comment.setUserId(dto.getUserId());
            comment.setCourseVideoId(dto.getVideoId());
            comment.setContent(dto.getContent());
            comment.setCreateTime(new Date());
            comment.setDeleted(0);
            baseMapper.insert(comment);
        }
    }

    /**
     * 获取视频评论总条数
     */
    @Override
    public Long getCommentCount(Long videoId) {
        String countKey = RedisConstant.VIDEO_COMMENT_COUNT_PREFIX + videoId;
        Object value = redisTemplate.opsForValue().get(countKey);

        if (value != null) {
            return ((Number) value).longValue();
        }

        Long count = baseMapper.selectCount(Wrappers.<BizCourseVideoComment>lambdaQuery()
                .eq(BizCourseVideoComment::getCourseVideoId, videoId)
                .eq(BizCourseVideoComment::getDeleted, 0));
        redisTemplate.opsForValue().set(countKey, count, 7, TimeUnit.DAYS);
        return count;
    }

    /**
     * 删除评论（Long类型ID适配，验证权限）
     */
    @Override
    public boolean deleteComment(Long commentId, Long videoId, Long userId) { // 入参改为Long类型
        // 1. 构建Redis评论键（使用Long类型ID）
        String commentKey = RedisConstant.VIDEO_COMMENT_PREFIX + videoId + ":" + commentId;

        // 2. 验证评论所有权
        VideoCommentDTO redisComment = null;
        Object redisCommentObj = redisTemplate.opsForValue().get(commentKey);
        if (redisCommentObj instanceof VideoCommentDTO) {
            redisComment = (VideoCommentDTO) redisCommentObj;
            if (!Objects.equals(redisComment.getUserId(), userId)) {
                throw new SecurityException("无权删除他人评论");
            }
        } else {
            // 从数据库查询评论（Long类型ID匹配）
            BizCourseVideoComment dbComment = baseMapper.selectOne(Wrappers.<BizCourseVideoComment>lambdaQuery()
                    .eq(BizCourseVideoComment::getId, commentId) // 直接使用Long类型ID查询
                    .eq(BizCourseVideoComment::getCourseVideoId, videoId)
                    .eq(BizCourseVideoComment::getDeleted, 0));

            if (dbComment == null) {
                throw new IllegalArgumentException("评论不存在");
            }
            if (!Objects.equals(dbComment.getUserId(), userId)) {
                throw new SecurityException("无权删除他人评论");
            }
        }

        // 删除Redis中的评论
        boolean redisDeleted = redisTemplate.delete(commentKey);

        // 调整评论计数
        String countKey = RedisConstant.VIDEO_COMMENT_COUNT_PREFIX + videoId;
        redisTemplate.opsForValue().decrement(countKey, 1);

        //  修正计数为非负
        Object currentCount = redisTemplate.opsForValue().get(countKey);
        if (currentCount instanceof Number && ((Number) currentCount).longValue() < 0) {
            redisTemplate.opsForValue().set(countKey, 0L);
        }

        //逻辑删除数据库中的评论（Long类型ID）
        int dbDeleted = baseMapper.update(null, Wrappers.<BizCourseVideoComment>lambdaUpdate()
                .set(BizCourseVideoComment::getDeleted, 1)
                .set(BizCourseVideoComment::getDeletedTime, LocalDateTime.now())
                .eq(BizCourseVideoComment::getId, commentId) // Long类型ID匹配
                .eq(BizCourseVideoComment::getCourseVideoId, videoId)
                .eq(BizCourseVideoComment::getUserId, userId));

        //重试机制确保Redis删除
        if (!redisDeleted && dbDeleted > 0) {
            redisTemplate.opsForValue().set(RedisConstant.DELETE_RETRY_QUEUE + commentKey,
                    System.currentTimeMillis(), 10, TimeUnit.SECONDS);
        }

        return redisDeleted || dbDeleted > 0;
    }

    @Override
    @Scheduled(cron = "0 0/1 * * * ?")
    public void syncComments() {
        syncCommentsToDb();
        retryFailedRedisDeletions();
    }

    /**
     * 重试删除失败的Redis评论
     */
    private void retryFailedRedisDeletions() {
        String pattern = RedisConstant.DELETE_RETRY_QUEUE + "*";
        redisTemplate.keys(pattern).forEach(key -> {
            String originalKey = key.replace(RedisConstant.DELETE_RETRY_QUEUE, "");
            redisTemplate.delete(originalKey);
            redisTemplate.delete(key);
        });
    }

    /**
     * 生成Long类型评论ID（可替换为雪花算法或数据库自增）
     */
    private Long generateLongCommentId() {
        // 方案1：使用时间戳+随机数（简单实现，生产环境建议用雪花算法）
        long timestamp = System.currentTimeMillis();
        long random = (long) (Math.random() * 1000);
        return timestamp + random;

    }

    public static class RedisConstant {
        public static final String VIDEO_COMMENT_PREFIX = "video:comment:";
        public static final String COMMENT_SYNC_QUEUE = "comment:sync:queue";
        public static final String VIDEO_COMMENT_COUNT_PREFIX = "video:comment:count:";
        public static final String DELETE_RETRY_QUEUE = "comment:delete:retry:";
    }
}